package com.bckj.fastboot.flow.process.consumer;

import com.bckj.fastboot.core.lang.exception.BusinessException;
import com.bckj.fastboot.core.operation.Operation;
import com.bckj.fastboot.core.operation.context.OperationContext;
import com.bckj.fastboot.core.operation.context.OperationLinkedHashMap;
import com.bckj.fastboot.core.util.ExecutionContext;
import com.bckj.fastboot.core.util.SpringUtils;
import com.bckj.fastboot.flow.model.BpmnCallActivity;
import com.bckj.fastboot.flow.model.BpmnIOParam;
import com.bckj.fastboot.flow.model.BpmnServiceTask;
import com.bckj.fastboot.flow.process.BpmnElResolver;
import com.bckj.fastboot.flow.process.BpmnProcessExecutor;
import com.bckj.fastboot.flow.process.expression.CustomExpressionProcessor;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.List;

@Slf4j
@Component
@Scope("prototype")
public class CustomBpmnProcessConsumer implements BpmnProcessConsumer {

    @Resource
    private CustomExpressionProcessor customExpressionProcessor;
    @Resource
    private Environment environment;
    private final List<Operation> successfulOps = new ArrayList<>();
    private final BpmnElResolver bpmnElResolver = new BpmnElResolver();

    @Override
    public void consume(ExecutionContext context, BpmnServiceTask serviceTask) {
        String expression = serviceTask.getExpression();
        if (expression != null && !expression.isBlank()) {
            //执行表达式
            log.debug("Execute expression: " + expression);
            Object result = customExpressionProcessor.evaluate(expression, context);
            log.debug("Result: " + result);
            return;
        }
        String delegateClass = serviceTask.getDelegateClass();
        if (delegateClass != null && !delegateClass.isBlank()) {
            log.debug("Execute delegateClass: " + delegateClass);
            try {
                Class<?> clazz = Class.forName(delegateClass);
                Operation operation = getOperation(clazz);
                operation.execute((OperationContext) context);
                successfulOps.add(operation);
            } catch (Exception e) {
                throw new BusinessException("DelegateClass is error, delegateClass=" + serviceTask.getDelegateClass());
            }
            return;
        }
        String delegateExpression = serviceTask.getDelegateExpression();
        if (delegateExpression != null && !delegateExpression.isBlank()) {
            log.debug("Execute delegateExpression: " + delegateExpression);

            if (delegateExpression.startsWith("${op:")) {
                String operationName = delegateExpression.substring(5, delegateExpression.length() - 1);
                Operation operation = getOperation(operationName);
                if (operation == null) {
                    throw new BusinessException("operation is null, operationName=" + operationName);
                }
                operation.execute((OperationContext) context);
                successfulOps.add(operation);
                return;
            }
            // 模拟解析逻辑（实际需注入Environment）
            String beanName = PROPERTY_PLACEHOLDER_HELPER.replacePlaceholders(delegateExpression, placeholder -> {
                if (environment.containsProperty(placeholder)) {
                    return environment.getProperty(placeholder);
                }
                return placeholder;
            });
            Operation operation = getOperation(beanName);
            if (operation == null) {
                throw new BusinessException("operation is null, operationName=" + beanName);
            }
            operation.execute((OperationContext) context);
            successfulOps.add(operation);
        }
    }

    @Override
    public void consume(ExecutionContext context, BpmnCallActivity callActivity) {
        BpmnProcessExecutor processExecutor = SpringUtils.getBean(BpmnProcessExecutor.class);
        OperationContext subCtx = OperationLinkedHashMap.of();
        if (callActivity.getInParams() != null) {
            // 输入映射（父→子）
            for (BpmnIOParam param : callActivity.getInParams()) {
                String source = param.getSourceExpression() != null ? getValue(param.getSourceExpression(),  context) : param.getSource();
                String target = param.getTargetExpression() != null ? getValue(param.getTargetExpression(),  context) : param.getTarget();
                Assert.hasText(source, "输入映射源不能为空");
                Assert.hasText(target, "输入映射目标不能为空");
                Object value = context.get(source);
                subCtx.put(target, value);
            }
        }
        processExecutor.execute(callActivity.getCalledElement(), subCtx, this);
        if (callActivity.getOutParams() != null) {
            // 输出映射（子→父）
            for (BpmnIOParam param : callActivity.getInParams()) {
                String source = param.getSourceExpression() != null ? getValue(param.getSourceExpression(),  context) : param.getSource();
                String target = param.getTargetExpression() != null ? getValue(param.getTargetExpression(),  context) : param.getTarget();
                Assert.hasText(source, "输出映射源不能为空");
                Assert.hasText(target, "输出映射目标不能为空");
                Object value = subCtx.get(source);
                context.put(target, value);
            }
        }
    }

    private String getValue(String expression, ExecutionContext context) {
        String result = bpmnElResolver.getValue(context, expression, String.class);
        log.debug("Result: " + result);
        return result;
    }

    private Operation getOperation(String beanName) {
        return (Operation) SpringUtils.getBean(beanName);
    }

    private Operation getOperation(Class<?> clazz) {
        return (Operation) SpringUtils.getBean(clazz);
    }

    @Override
    public void callback(ExecutionContext context) {

        for (int i = successfulOps.size() - 1; i >= 0; i--) {
            try {
                Operation operation = successfulOps.get(i);
                operation.callback((OperationContext) context);
            } catch (Exception e) {
                log.error("执行流程回调异常", e);
            }
        }
    }

    @Override
    public void rollback(ExecutionContext context, Throwable error) {
        for (int i = successfulOps.size() - 1; i >= 0; i--) {
            try {
                Operation operation = successfulOps.get(i);
                operation.rollback((OperationContext) context, error);
            } catch (Exception e) {
                log.error("执行流程回滚异常", e);
            }
        }
    }
}
